/**
 * Copyright (C) 2013 DaiKit.com - daikit4gxt module (admin@daikit.com)
 *
 *         Project home : http://code.daikit.com/daikit4gxt
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.daikit.daikit4gxt.client;

import java.util.ArrayList;
import java.util.List;

import com.daikit.commons.shared.utils.DkObjectUtils;
import com.daikit.daikit4gxt.client.labelprovider.DkAsSimpleStringLabelProvider;
import com.sencha.gxt.data.shared.LabelProvider;
import com.sencha.gxt.data.shared.ListStore;
import com.sencha.gxt.data.shared.ModelKeyProvider;


/**
 * A cache entity to store cached list of beans and provide chain Action needed to reload it.
 * 
 * @author tcaselli
 * @version $Revision$ Last modifier: $Author$ Last commit: $Date$
 * @param <B>
 *           the type of the bean stored as a list in the cache entity
 */
public class DkCacheEntity<B>
{
	private boolean loaded = false;
	private final List<B> list = new ArrayList<B>();
	private final ModelKeyProvider<? super B> modelKeyProvider;
	private final LabelProvider<? super B> labelProvider;
	private final List<ListStore<B>> bindedListStores = new ArrayList<ListStore<B>>();

	/**
	 * Create a new Cache entity with a {@link DkAsSimpleStringLabelProvider}
	 * 
	 * @param modelKeyProvided
	 */
	public DkCacheEntity(final ModelKeyProvider<? super B> modelKeyProvided)
	{
		this(modelKeyProvided, new DkAsSimpleStringLabelProvider<B>());
	}

	/**
	 * Create a new cache entity
	 * 
	 * @param modelKeyProvider
	 *           the modelKeyProvider
	 * @param labelProvider
	 *           the labeProvider
	 */
	public DkCacheEntity(final ModelKeyProvider<? super B> modelKeyProvider, final LabelProvider<? super B> labelProvider)
	{
		this.modelKeyProvider = modelKeyProvider;
		this.labelProvider = labelProvider;
	}

	/**
	 * Update the cache with given list of models
	 * 
	 * @param models
	 *           a {@link List} of models
	 */
	public void update(final List<B> models)
	{
		list.clear();
		list.addAll(models);
		loaded = true;
		for (final ListStore<B> store : bindedListStores)
		{
			store.clear();
			store.addAll(list);
		}
	}

	/**
	 * @return the loaded
	 */
	public boolean isLoaded()
	{
		return loaded;
	}

	/**
	 * Create a {@link ListStore} and populate it with this cache data.
	 * 
	 * @return the created {@link ListStore}
	 */
	public ListStore<B> createListStore()
	{
		final ListStore<B> store = new ListStore<B>(getModelKeyProvider());
		store.addAll(list);
		bindedListStores.add(store);
		return store;
	}

	/**
	 * @return the list
	 */
	public List<B> getList()
	{
		return list;
	}

	/**
	 * @return the modelKeyProvided the {@link ModelKeyProvider}
	 */
	public ModelKeyProvider<? super B> getModelKeyProvider()
	{
		return modelKeyProvider;
	}

	/**
	 * @return the labelProvider the {@link LabelProvider}
	 */
	public LabelProvider<? super B> getLabelProvider()
	{
		return labelProvider;
	}

	/**
	 * Get the model with given key
	 * 
	 * @param key
	 *           the key
	 * @return the model corresponding to given key
	 */
	public B get(final Object key)
	{
		B ret = null;
		loop: for (final B model : list)
		{
			if (DkObjectUtils.equalsWithNull(modelKeyProvider.getKey(model), key))
			{
				ret = model;
				break loop;
			}
		}
		return ret;
	}

	/**
	 * Get all keys for given objects
	 * 
	 * @return a {@link List} of keys
	 */
	@SuppressWarnings("unchecked")
	public <X> List<X> getAllKeys()
	{
		final List<X> allKeys = new ArrayList<X>();
		for (final B model : list)
		{
			allKeys.add((X) modelKeyProvider.getKey(model));
		}
		return allKeys;
	}

}
